﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;

namespace Gmantis.Controls.Chart
{
    public class ShadowEffect : VisualEffect
    {
        // Fields
        public static DependencyProperty ColorProperty = DependencyProperty.Register("Color", typeof(Color), typeof(ShadowEffect), new PropertyMetadata(Colors.Black, new PropertyChangedCallback(VisualEffect.OnChanged)));
        public static DependencyProperty DepthProperty = DependencyProperty.Register("Depth", typeof(double), typeof(ShadowEffect), new PropertyMetadata(4.0, new PropertyChangedCallback(VisualEffect.OnChanged)));
        public static DependencyProperty LightAngleProperty = DependencyProperty.Register("LightAngle", typeof(double), typeof(ShadowEffect), new PropertyMetadata(45.0, new PropertyChangedCallback(VisualEffect.OnChanged)));
        public static DependencyProperty OpacityProperty = DependencyProperty.Register("Opacity", typeof(double), typeof(ShadowEffect), new PropertyMetadata(0.4, new PropertyChangedCallback(VisualEffect.OnChanged)));
        public static DependencyProperty SoftnessProperty = DependencyProperty.Register("Softness", typeof(double), typeof(ShadowEffect), new PropertyMetadata(0.0, new PropertyChangedCallback(VisualEffect.OnChanged)));

        // Methods
        internal override UIElement CreateBackgroundEffect(Shape shape)
        {
            if (shape != null)
            {
                Geometry geom = base.GetGeometry(shape);
                if (geom != null)
                {
                    double strokeThickness = 0.0;
                    if (!VfxTools.IsFilled(geom))
                    {
                        strokeThickness = shape.StrokeThickness;
                    }
                    UIElement element = CreateShadow(geom, this.Color, this.Opacity, this.LightAngle, this.Depth, this.Softness, strokeThickness);
                    if (element != null)
                    {
                        element.Opacity = shape.Opacity;
                        element.IsHitTestVisible = false;
                        return element;
                    }
                }
            }
            return null;
        }

        private static Canvas CreateShadow(Geometry g, Color clr, double opacity, double angle, double offset, double softness, double strokeThickness)
        {
            Canvas canvas = new Canvas();
            if (offset > 0.0)
            {
                if (double.IsNaN(angle))
                {
                    if (softness > 0.0)
                    {
                        double num = 0.0;
                        for (int i = (int)offset; i > 0; i--)
                        {
                            double num3 = (((offset - i) + 1.0) / offset) * opacity;
                            if (num != 0.0)
                            {
                                num = num3 - num;
                            }
                            else
                            {
                                num = num3;
                            }
                            SolidColorBrush brush = new SolidColorBrush(clr)
                            {
                                Opacity = num
                            };
                            Path path = new Path
                            {
                                Fill = brush
                            };
                            path.Stroke = brush;
                            path.StrokeThickness = 2 * i;
                            path.StrokeLineJoin = PenLineJoin.Round;
                            path.Data = VfxTools.CloneGeometry(g);
                            canvas.Children.Add(path);
                        }
                        return canvas;
                    }
                    SolidColorBrush brush2 = new SolidColorBrush(clr)
                    {
                        Opacity = opacity
                    };
                    Path path3 = new Path
                    {
                        Fill = brush2
                    };
                    path3.Stroke = brush2;
                    path3.Data = VfxTools.CloneGeometry(g);
                    path3.StrokeLineJoin = PenLineJoin.Round;
                    path3.StrokeThickness = 2.0 * offset;
                    canvas.Children.Add(path3);
                    return canvas;
                }
                angle *= 0.017453292519943295;
                if (softness > 0.0)
                {
                    double num4 = 0.0;
                    for (int j = (int)offset; j > 0; j--)
                    {
                        double num6 = (((offset - j) + 1.0) / offset) * opacity;
                        if (num4 != 0.0)
                        {
                            num4 = num6 - num4;
                        }
                        else
                        {
                            num4 = num6;
                        }
                        SolidColorBrush brush3 = new SolidColorBrush(clr)
                        {
                            Opacity = num4
                        };
                        Path path5 = new Path
                        {
                            Fill = brush3
                        };
                        if (strokeThickness > 0.0)
                        {
                            path5.Stroke = brush3;
                            path5.StrokeThickness = strokeThickness;
                        }
                        TranslateTransform transform = new TranslateTransform
                        {
                            X = j * Math.Cos(angle),
                            Y = -j * Math.Sin(angle)
                        };
                        path5.RenderTransform = transform;
                        path5.Data = VfxTools.CloneGeometry(g);
                        canvas.Children.Add(path5);
                    }
                    return canvas;
                }
                SolidColorBrush brush4 = new SolidColorBrush(clr)
                {
                    Opacity = opacity
                };
                Path path7 = new Path
                {
                    Fill = brush4
                };
                if (strokeThickness > 0.0)
                {
                    path7.Stroke = brush4;
                    path7.StrokeThickness = strokeThickness;
                }
                TranslateTransform transform2 = new TranslateTransform
                {
                    X = offset * Math.Cos(angle),
                    Y = -offset * Math.Sin(angle)
                };
                path7.RenderTransform = transform2;
                path7.Data = VfxTools.CloneGeometry(g);
                canvas.Children.Add(path7);
            }
            return canvas;
        }

        // Properties
        public Color Color
        {
            get
            {
                return (Color)base.GetValue(ColorProperty);
            }
            set
            {
                base.SetValue(ColorProperty, value);
            }
        }

        public double Depth
        {
            get
            {
                return (double)base.GetValue(DepthProperty);
            }
            set
            {
                base.SetValue(DepthProperty, value);
            }
        }

        public double LightAngle
        {
            get
            {
                return (double)base.GetValue(LightAngleProperty);
            }
            set
            {
                base.SetValue(LightAngleProperty, value);
            }
        }

        public double Opacity
        {
            get
            {
                return (double)base.GetValue(OpacityProperty);
            }
            set
            {
                base.SetValue(OpacityProperty, value);
            }
        }

        public double Softness
        {
            get
            {
                return (double)base.GetValue(SoftnessProperty);
            }
            set
            {
                base.SetValue(SoftnessProperty, value);
            }
        }
    }
}
